package com.ldgk.pim.server;

import java.util.ArrayList;
import java.util.List;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.GeoPt;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.ldgk.pim.client.rpc.PlacesService;
import com.ldgk.pim.client.util.GeoHash;
import com.ldgk.pim.data.Place;

@SuppressWarnings("serial")
/**
 * PlacesService server-side implementation
 */
public class PlacesServiceImpl extends RemoteServiceServlet implements PlacesService {

	/**
	 * {@inheritDoc}
	 */
	public void persist(Place place) {
		DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
		Entity e = placeToEntity(place);
		// Save or update
		ds.put(e);
	}

	/**
	 * {@inheritDoc}
	 */
	public void delete(Place place) {
		DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
		Entity e = placeToEntity(place);
		ds.delete(e.getKey());
	}

	/**
	 * {@inheritDoc}
	 */
	public List<Place> findInsideBox(double sla, double sln, double ela, double eln) {
		String topLeftCorner = GeoHash.fromLatLng(sla, sln).toBase32();
		String bottonRightCorner = GeoHash.fromLatLng(ela, eln).toBase32();

		DatastoreService ds = DatastoreServiceFactory.getDatastoreService();

		Query q = new Query("Place");
		q.addFilter("geohash", Query.FilterOperator.LESS_THAN_OR_EQUAL, topLeftCorner);
		q.addFilter("geohash", Query.FilterOperator.GREATER_THAN_OR_EQUAL, bottonRightCorner);

		PreparedQuery pq = ds.prepare(q);

		ArrayList<Place> lista = new ArrayList<Place>();
		for (Entity entity : pq.asIterable()) {
			lista.add(entityToPlace(entity));
		}
		return lista;
	}

	/**
	 * Converts a place datastore Entity to a Place object
	 * @param e - datastore entity
	 * @return new Place instance
	 */
	private Place entityToPlace(Entity e) {
		Place p = new Place();

		p.setKey(e.getKey().getId());
		p.setName((String) e.getProperty("name"));
		p.setAddress((String) e.getProperty("address"));
		p.setContactPerson((String) e.getProperty("contactPerson"));
		p.setDetails((String) e.getProperty("details"));
		p.setEmail((String) e.getProperty("email"));
		p.setPhones((String) e.getProperty("phones"));
		p.setType(Integer.parseInt((String)e.getProperty("type")));
		p.setGeoHash((String) e.getProperty("geohash"));

		GeoPt point = (GeoPt) e.getProperty("point");
		p.setLat(point.getLatitude());
		p.setLng(point.getLongitude());

		return p;
	}

	/**
	 * Converts a Place instance to a datastore entity
	 * @param p - Place entity
	 * @return - datastore entity
	 */
	private Entity placeToEntity(Place p) {
		Entity e = null;
		if (p.getKey() != -1) {
			//If there is an existent key, create a Key based on that (update/delete)
			Key key = KeyFactory.createKey("Place", p.getKey());
			e = new Entity(key);
		} else {
			//Create a new entity (create)
			e = new Entity("Place");
		}

		e.setProperty("name", p.getName());
		e.setProperty("address", p.getAddress());
		e.setProperty("contactPerson", p.getContactPerson());
		e.setProperty("details", p.getDetails());
		e.setProperty("email", p.getEmail());
		e.setProperty("phones", p.getPhones());
		e.setProperty("type", Integer.toString(p.getType()));
		e.setProperty("point", new GeoPt((float) p.getLat(), (float) p.getLng()));
		e.setProperty("geohash", p.getGeoHash());

		return e;
	}
}
